package com.db.chat.server;

import com.db.chat.logging.AbstractLogger;
import com.db.chat.server.history.HistoryHandler;
import com.db.chat.server.history.HistoryWriteException;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * Created by Student on 25.11.2014.
 */
public class ControllerThread implements Runnable {
    private Map<String, List<String>> messageList = new HashMap<>();
    private List<Transport> transportList = new LinkedList<Transport>();
    private HistoryHandler hHandler;
    private AbstractLogger logger;

    public ControllerThread(HistoryHandler hHandler, AbstractLogger logger) {
        this.logger = logger;
        this.hHandler = hHandler;
    }

    public void newBroadcastMessage(String roomName, String message) {
        synchronized (messageList) {
            if (messageList.get(roomName) != null) {
                messageList.get(roomName).add(message);
            }
            else {
                messageList.put(roomName, new LinkedList<>());
                messageList.get(roomName).add(message);
            }
            messageList.notify();
        }
    }

    public void newNetwork(Transport transport) {
        synchronized (transportList) {
            transportList.add(transport);
        }
    }

    @Override
    public void run() {
        logger.write("Started controller");
        while (true) {

            String message = null;
            boolean broadcastIsEmpty = true;

            for (String roomName : messageList.keySet()) {
                if ((message = getBroadcastMessage(roomName)) != null) {
                    broadcastIsEmpty = false;
                    logger.write("Controller sending broadcast "+message);

                    try {
                        hHandler.write(message);
                    } catch (HistoryWriteException e) {
                        logger.write("Failed to write history msg: "+message + " exception "+e.getMessage());
                    }
                    broadcastAndRemoveDisconnected(roomName, message);
                }
            }

            synchronized (messageList) {
                if (broadcastIsEmpty) {
                    try {
                        messageList.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }


        }
    }

    private void broadcastAndRemoveDisconnected(String roomName, String message) {
        synchronized (transportList) {
            for (int i = 0; i < transportList.size(); i++) {
                Transport transport = transportList.get(i);
                if (transport.getMarked()){
                    transportList.remove(0);
                    i--;
                    continue;
                }

                try {
                    logger.write("Controller sending ..");
                    if (transport.getRoomName().equals(roomName)) {
                        transport.send(message);
                    }
                } catch (TransportException e) {
                    try {
                        transport.close();
                    } catch (TransportException e1) {
                        //Supressing exception!
                    }
                }
            }
        }
    }

    private String getBroadcastMessage(String roomName) {

        synchronized (messageList) {


            if (messageList.get(roomName).isEmpty()) {
                return null;
            }
            else {
                return messageList.get(roomName).remove(0);
            }
        }

    }
}